﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Common;
using System.Windows.Forms.DataVisualization.Charting;
using System.Data.SQLite;
namespace YourMoney
{
    public partial class DiagramForm : Form
    {
        int typeOfDiagram;
        /// <summary>
        /// Создание формы и установка типа диаграммы
        /// </summary>
        /// <param name="TypeOfDiagram"></param>
        public DiagramForm(int TypeOfDiagram)
        {
            InitializeComponent();
            this.Invalidate();
            this.typeOfDiagram = TypeOfDiagram;
        }


        int parametrOfDetalization = 0;
        int countOfDiagrams = 0;
        List<string> arrayOfSumm = new List<string>();
        List<string> arrayOfName = new List<string>();
        List<string> arrayOfType = new List<string>();
        List<Color> arrayOfColor = new List<Color>();
        List<DateTime> arrayOfDate = new List<DateTime>();

        /// <summary>
        /// Выборка данных из БД для построения даиграммы
        /// </summary>
        private void DiagFormSelect()
        {
            List<TreeNode> checkedList = new List<TreeNode>();
            foreach (TreeNode node in typeTreeView.Nodes)
            {
                SelectCheckedNodes(node, checkedList);
            }

            countOfDiagrams = 0;
            arrayOfDate.Clear();
            arrayOfType.Clear();
            arrayOfName.Clear();
            arrayOfSumm.Clear();
            arrayOfColor.Clear();

            SQLiteDriver drv = SQLiteDriver.GetDrv("Money.db3");
            string command = @"SELECT  tec.name,t.name,e.size,date(e.date, 'unixepoch') 'date' ,t.color 
                  FROM Essence e
                  JOIN TypeOfEssence t  ON e.type_id = t.id join TypeOfEssence tec ON t.root_id=tec.id 
                  where datetime(e.date, 'unixepoch')>=datetime('" + ((dateStartPicker.Value - new DateTime(1970, 1, 1)).TotalSeconds) + "','unixepoch') AND datetime(e.date, 'unixepoch')<=datetime('" + ((dateFinishPicker.Value - new DateTime(1970, 1, 1)).TotalSeconds) + "','unixepoch') order by 4;";

            string nodeSelectCommand = "AND t.id IN ()";
            foreach (TreeNode node in checkedList)
            {
                nodeSelectCommand = nodeSelectCommand.Insert(nodeSelectCommand.IndexOf(")"), ((TypeOfEssence)node.Tag).ID.ToString() + ", ");

            }
            nodeSelectCommand = nodeSelectCommand.Remove(nodeSelectCommand.LastIndexOf(","), 1);
            int c = nodeSelectCommand.Length;
            command = command.Insert(command.IndexOf("order"), nodeSelectCommand + " ");

            foreach (DbDataRecord record in drv.Query(command))
            {
                int tmpsumm = int.Parse(record[2].ToString());

                arrayOfDate.Add(DateTime.Parse(record["date"].ToString()));//DateTime.Parse(record[3].ToString());
                arrayOfType.Add(record[0].ToString());
                arrayOfName.Add(record[1].ToString());
                arrayOfSumm.Add(record[2].ToString());
                arrayOfColor.Add(Color.FromArgb(Convert.ToInt32(record["color"])));

                countOfDiagrams++;
            }
        }

        /// <summary>
        /// Заполнение treeview значениями типов сущностей
        /// </summary>
        void FillTreeView()
        {
            typeTreeView.Nodes.Clear();
            List<TreeNode> rootsList = StaticMembers.RootEssenceSelect();
            for (int i = 0; i < rootsList.Count; i++)
            {
                StaticMembers.SetEssenceTree(rootsList[i]);
                typeTreeView.Nodes.Add(rootsList[i]);

            }
            typeTreeView.ExpandAll();
        }
        /// <summary>
        /// Определение интервала между date1 b и date2 в днях
        /// </summary> 
        public static int DaysDiff(DateTime date1, DateTime date2)
        {
            return date1.Subtract(date2.Date).Days;
        }

        /// <summary>
        ///Определение кол-ва дней от minDate до maxDate
        /// </summary>
        /// <returns>Число дней </returns>
        int Interval()
        {
            return DaysDiff(dateFinishPicker.Value, dateStartPicker.Value);
        }
        /// <summary>
        ///Определение кол-ва дней от minDate до введенной даты x 
        ///
        /// </summary>
        /// <param name="x">Дата</param>
        /// <returns>Целое число дней</returns>
        int IntervalStart(DateTime x)
        {
            return DaysDiff(x, dateStartPicker.Value);
        }
        /// <summary>
        ///Определение имени месяца
        /// </summary>
        /// <param name="month">Порядковый номер месяца</param>
        /// <returns>Имя месяца</returns>
        string ReturnNameOfMonth(int month)
        {
            string[] months = new string[12] { "Январь", "Февраль", "Март", "Апрель", "Май", "Июнь", "Июль", "Август", "Сентябрь", "Октябрь", "Ноябрь", "Декабрь" };
            return months[month - 1];
        }

        //переменные для кол-ва дней
        int interval;
        //детализация по параметру p
        //global аррэи это для гистограммы т.к у нас меняеться countOfDiagrams на увелечение и мы уже не можем использовать его
        //теперь у нас кол-во диаграм завит от заданного промежутка времени interal
        List<double> arrayOfGlobalSumm = new List<double>();
        List<Color> arrayOfGlobalColor = new List<Color>();
        List<DateTime> arrayOfGlobalTime = new List<DateTime>();

        //для параметра детализации по месяцам 
        //чтобы выводить название месяца и года нужны эти два массива
        List<string> arrayOfMonth = new List<string>();
        List<int> arrayOfYear = new List<int>();
        List<DateTime> arrayOfWeekTime1 = new List<DateTime>();
        List<DateTime> arrayOfWeekTime2 = new List<DateTime>();

        /// <summary>
        /// Детализация гистограммы
        /// </summary>
        /// <param name="p">Параметр детализации(0-по дням; 1 - по неделям; 2 - по месяцам)</param>
        void Detalization(int p)
        {
            arrayOfGlobalSumm.Clear();
            arrayOfGlobalColor.Clear();
            arrayOfGlobalTime.Clear();
            arrayOfMonth.Clear();
            arrayOfYear.Clear();
            arrayOfWeekTime1.Clear();
            arrayOfWeekTime2.Clear();

            DateTime tmpDate = new DateTime();
            interval = Interval() + 1;
            List<int> arrayOfDay = new List<int>();
            List<double> tarrayOfGlobalSumm = new List<double>();

            tmpDate = dateStartPicker.Value;
            arrayOfWeekTime1.Add(tmpDate);


            arrayOfMonth.Add(ReturnNameOfMonth(tmpDate.Month));
            arrayOfYear.Add(tmpDate.Year);

            Random r = new Random();
            
            for (int i = 0; i < countOfDiagrams; i++)
            {
                arrayOfDay.Add(IntervalStart(arrayOfDate[i]));
            }

            switch (p)
            {
                case 0:
                    for (int i = 0; i < interval; i++)
                    {
                        tarrayOfGlobalSumm.Add(0);
                        arrayOfGlobalColor.Add(Color.White);
                        arrayOfGlobalTime.Add(tmpDate);
                        for (int j = 0; j < countOfDiagrams; j++)
                        {
                            if (i == arrayOfDay[j])
                            {

                                tarrayOfGlobalSumm[i] = int.Parse(arrayOfSumm[j]);
                                arrayOfGlobalColor[i] = arrayOfColor[j];
                            }


                        }
                        tmpDate = tmpDate.AddDays(1);


                    }
                    for (int k = 0; k < interval; k++)
                    {
                        arrayOfGlobalSumm.Add(tarrayOfGlobalSumm[k]);
                    };

                    arrayOfDay.Clear();
                    tarrayOfGlobalSumm.Clear();

                    break;
                case 1:
                    for (int i = 0; i < interval; i++)
                    {
                        tarrayOfGlobalSumm.Add(0);
                        for (int j = 0; j < countOfDiagrams; j++)
                        {
                            if (i == arrayOfDay[j])
                            {
                                tarrayOfGlobalSumm[i] = int.Parse(arrayOfSumm[j]);
                            }
                        }
                    }
                    int w = 1;
                    double tmpw = 0;
                    for (int k = 0; k < interval; k++)
                    {
                        tmpw = tmpw + tarrayOfGlobalSumm[k];
                        if (tmpDate.DayOfWeek.ToString() == "Sunday")
                        {
                            arrayOfGlobalSumm.Add(tmpw);
                            for (int j = 0; j < countOfDiagrams; j++)
                                arrayOfGlobalColor.Add(Color.FromArgb(r.Next(0, 255), r.Next(0, 255), r.Next(0, 255)));//W-1
                            arrayOfWeekTime2.Add(tmpDate);
                            tmpw = 0;
                            w++;
                            arrayOfWeekTime1.Add(tmpDate.AddDays(1));
                        }
                        tmpDate = tmpDate.AddDays(1);

                    }
                    arrayOfGlobalSumm.Add(tmpw);
                    for (int j = 0; j < countOfDiagrams; j++)
                        arrayOfGlobalColor.Add(Color.FromArgb(r.Next(0, 255), r.Next(0, 255), r.Next(0, 255)));
                    arrayOfWeekTime2.Add(dateFinishPicker.Value);
                    interval = w;

                    arrayOfDay.Clear();
                    tarrayOfGlobalSumm.Clear();

                    break;
                case 2:
                    for (int i = 0; i < interval; i++)
                    {
                        tarrayOfGlobalSumm.Add(0);
                        for (int j = 0; j < countOfDiagrams; j++)
                        {
                            if (i == arrayOfDay[j])
                            {
                                tarrayOfGlobalSumm[i] = int.Parse(arrayOfSumm[j]);
                            }
                        }
                    }
                    int m = 1;
                    double tmpm = 0;
                    int month = tmpDate.Month;
                    int year = tmpDate.Year;
                    for (int k = 0; k < interval; k++)
                    {
                        tmpm = tmpm + tarrayOfGlobalSumm[k];
                        if (tmpDate.Month != month || tmpDate.Year != year)
                        {
                            arrayOfMonth.Add(ReturnNameOfMonth(tmpDate.Month));
                            arrayOfYear.Add(tmpDate.Year);

                            month = tmpDate.Month;
                            year = tmpDate.Year;

                            arrayOfGlobalSumm.Add(tmpm);
                            arrayOfGlobalColor.Add(Color.FromArgb(r.Next(0, 255), r.Next(0, 255), r.Next(0, 255)));
                            //tmpw = tarrayOfGlobalSumm[k];
                            tmpm = 0;
                            m++;

                        }
                        tmpDate = tmpDate.AddDays(1);


                    }
                    arrayOfGlobalColor.Add(Color.FromArgb(r.Next(0, 255), r.Next(0, 255), r.Next(0, 255)));
                    arrayOfGlobalSumm.Add(tmpm);
                    interval = m;

                    arrayOfDay.Clear();
                    tarrayOfGlobalSumm.Clear();

                    break;
                default: MessageBox.Show("Sorry этого просто не может быть!");
                    break;
            }
        }
        /// <summary>
        /// Отрисовка диаграммы
        /// </summary>
        /// <param name="s">Тип диаграммы</param>
        void ChartDiaGramm(SeriesChartType s)
        {
            chart1.Series.Clear();
            Detalization(parametrOfDetalization);
            chart1.Series.Add(new Series());
            chart1.Series[0].Name = "";
            chart1.Series[0].Color = Color.White;
            chart1.Series[0].ChartType = s;
            //chart1.BorderlineColor = Color.Green;

            for (int i = 0; i < interval; i++)
            {
                chart1.Series[0].Points.Add(arrayOfGlobalSumm[i]);
                chart1.Series[0].Points[i].Color = arrayOfGlobalColor[i];//arrayOfColor[i];
                switch (parametrOfDetalization)
                {
                    case 0: chart1.Series[0].Points[i].AxisLabel = arrayOfGlobalTime[i].Day.ToString() + " " + ReturnNameOfMonth(arrayOfGlobalTime[i].Month) + " " + arrayOfGlobalTime[i].Year; break;//nameOfDetalization + i;
                    case 1: chart1.Series[0].Points[i].AxisLabel = arrayOfWeekTime1[i].Day.ToString() + "/" + arrayOfWeekTime1[i].Month + "/" + arrayOfWeekTime1[i].Year + "   " + arrayOfWeekTime2[i].Day + "/" + arrayOfWeekTime2[i].Month + "/" + arrayOfWeekTime2[i].Year; break;
                    case 2: chart1.Series[0].Points[i].AxisLabel = arrayOfMonth[i] + " " + arrayOfYear[i]; break;
                    default: MessageBox.Show("Это сообщение не должно было показаться)!"); break;
                }

            }
            chart1.Series[0]["PointWidth"] = "1";// Show data points labels
            //   chart1.Series[0].IsValueShownAsLabel = true;// Set data points label style
            chart1.Series[0]["BarLabelStyle"] = "Center";// Show chart as 3D
            chart1.ChartAreas[0].Area3DStyle.Enable3D = true;// Draw chart as 3D 

        }
        /// <summary>
        /// Отрисовка круговой диаграммы
        /// </summary>
        void ChartCircleDiagramm()
        {
            chart1.Series.Clear();
            chart1.Series.Add(new Series());
            List<double> tmps = new List<double>();
            chart1.Series[0].ChartType = SeriesChartType.Pie;

            for (int i = 0; i < countOfDiagrams; i++)
            {
                tmps.Add(int.Parse(arrayOfSumm[i]));
                chart1.Series[0].Points.Add(tmps[i]);
                chart1.Series[0].Points[i].Color = arrayOfColor[i];
                chart1.Series[0].Points[i].AxisLabel = arrayOfName[i] + " - " + tmps[i];
                chart1.Series[0].Points[i].BorderColor = Color.Aqua;
            }
            //  chart1.Series[0].ChartType = SeriesChartType.Pie;
            chart1.Series[0]["PointWidth"] = "1";// Show data points labels
            //chart1.Series[0].IsValueShownAsLabel = true;// Set data points label style
            chart1.Series[0]["BarLabelStyle"] = "Center";// Show chart as 3D
            chart1.ChartAreas[0].Area3DStyle.Enable3D = true;// Draw chart as 3D 

            countOfDiagrams = 0;

        }

        private void DiagForm_Load(object sender, EventArgs e)
        {
            SQLiteDriver drv = SQLiteDriver.GetDrv("Money.db3");
            //даты будут по дефолту минимум и максимум из того, что есть
            FillTreeView();
            typeTreeView.Nodes[0].Checked = true;
            CheckAllChildNodes(typeTreeView.Nodes[0], true);/*********/
            //устанавливаем комбобокс по умолчанию 1-по неделям
            comboBox1.SelectedItem = comboBox1.Items[1];
            DbDataReader reader = (drv.Query("select datetime(max(date),'unixepoch') 'date' from Essence;"));
            if (reader.RecordsAffected != 0)
            {
                dateFinishPicker.Value = DateTime.Parse(reader["date"].ToString());
            }
            reader = (drv.Query("select datetime(min(date),'unixepoch') 'date' from Essence;"));

            if (reader.RecordsAffected != 0)
            {
                dateStartPicker.Value = DateTime.Parse(reader["date"].ToString());
            }
            DiagFormSelect();
            switch (typeOfDiagram)
            {
                case 1:
                    ChartDiaGramm(SeriesChartType.Column);
                    break;

                case 2:
                    comboBox1.Dispose();
                    label1.Dispose();
                    ChartCircleDiagramm();
                    break;
            }

        }

        private CheckState Intermediate()
        {
            throw new NotImplementedException();
        }
        /// <summary>
        /// Работа с комбобоксом
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            // Save the selected employee's name, because we will remove
            // the employee's name from the list.

            string selectedEmployee = (string)comboBox1.SelectedItem;

            int resultIndex = 1;

            // Call the FindStringExact method to find the first 
            // occurrence in the list.
            resultIndex = comboBox1.FindStringExact(selectedEmployee);

            parametrOfDetalization = comboBox1.Items.IndexOf(selectedEmployee);
        }
        /// <summary>
        /// Нажатие клавиши
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {

            try
            {
                if (dateStartPicker.Value > dateFinishPicker.Value)
                    MessageBox.Show("Невозможные заданные параметры! попробуйте снова");

                DiagFormSelect();

                switch (typeOfDiagram)
                {
                    case 1:
                        ChartDiaGramm(SeriesChartType.Column);
                        break;

                    case 2:
                        comboBox1.Visible = false;
                        ChartCircleDiagramm();
                        break;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("Выберите поставьте галочки напротив нужных операций");
                this.Close();
            }
        }
        /// <summary>
        /// Выделение всех дочерних узлов в treeview 
        /// </summary>
        /// <param name="treeNode"></param>
        /// <param name="nodeChecked"></param>
        private void CheckAllChildNodes(TreeNode treeNode, bool nodeChecked)
        {
            foreach (TreeNode node in treeNode.Nodes)
            {
                node.Checked = nodeChecked;
                if (node.Nodes.Count > 0)
                {
                    this.CheckAllChildNodes(node, nodeChecked);
                }
            }
        }

        private void typeTreeView_AfterCheck(object sender, TreeViewEventArgs e)
        {
            if (e.Action != TreeViewAction.Unknown)
            {
                if (e.Node.Nodes.Count > 0)
                {
                    this.CheckAllChildNodes(e.Node, e.Node.Checked);
                }
            }
        }
        private List<TreeNode> SelectCheckedNodes(TreeNode parentNode, List<TreeNode> returnList)
        {
            //  List<TreeNode> returnList = new List<TreeNode>();
            if (parentNode.Checked) { returnList.Add(parentNode); }
            foreach (TreeNode node in parentNode.Nodes)
            {
                //    if (node.Checked) { returnList.Add(node); }
                SelectCheckedNodes(node, returnList);
            }
            return returnList;
        }

        private void chart1_Click(object sender, EventArgs e)
        {

        }

    }
}
